<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>fastmybatis开发文档</title>
        <link rel="stylesheet" href="./static/highlight/styles/vs.css">
		<script src="./static/highlight/highlight.pack.js"></script>
		<script>hljs.initHighlightingOnLoad();</script>
        <link rel="stylesheet" type="text/css" href="./static/github2-rightpart.css" media="all">
        <link rel="stylesheet" type="text/css" href="./static/github1-contents.css">
        <link rel="stylesheet" href="./static/zTreeStyle.css" type="text/css">
        <style>
            .ztree li a.curSelectedNode {
                padding-top: 0px;
                background-color: #FFE6B0;
                color: black;
                height: 16px;
                border: 1px #FFB951 solid;
                opacity: 0.8;
            }
            .ztree{
                overflow: auto;
                height:100%;
                min-height: 200px;
                top: 0px;
            }
            .task-list{list-style-type: disc !important;}
            .container{margin: 0px !important;}
            #readme .markdown-body, #readme .plain{border:0px !important;}
            .markdown-body{font-size:14px;}
        </style>
    </head>
    <body>
        <div>
            <div style="width:30%;">
                <ul id="tree" class="ztree" style="overflow: auto; position: fixed; z-index: 2147483647; border: 0px none; left: 0px; bottom: 0px;">
                <!-- 目录内容在网页另存为之后将插入到此处 -->
                </ul>
            </div>
            <div id="readme" style="width:70%;margin-left:25%;">
                <article class="markdown-body">


<!-- 请把你的html正文部分粘贴到此处，在浏览器中打开之后将会自动生成目录。如果想要将目录保留并嵌入到此文档中，只需在浏览器中“另存为->网页，全部”即可 -->
<div class="md-preview markdown-body" data-provider="markdown-preview" style="width: 100%; height: 21982px; resize: none;"><h1>简介</h1>
<p>fastmybatis是一个mybatis开发框架，其宗旨为：简单、快速、有效。</p>
<ul>
<li>零配置快速上手</li>
<li>无需编写xml文件即可完成CRUD操作</li>
<li>支持mysql，sqlserver，oracle，postgresql,sqlite</li>
<li>支持自定义sql，sql语句可写在注解中或xml中</li>
<li>支持与spring-boot集成，依赖starter即可</li>
<li>轻量级，无侵入性，是官方mybatis的一种扩展</li>
</ul>
<h1>快速开始（springboot）</h1>
<ul>
<li>新建一个springboot项目</li>
<li>pom.xml添加fastmybatis-spring-boot-starter</li>
</ul>
<pre><code class="hljs"><span class="hljs-tag">&lt;<span class="hljs-title">dependency</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-title">groupId</span>&gt;</span>net.oschina.durcframework<span class="hljs-tag">&lt;/<span class="hljs-title">groupId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-title">artifactId</span>&gt;</span>fastmybatis-spring-boot-starter<span class="hljs-tag">&lt;/<span class="hljs-title">artifactId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-title">version</span>&gt;</span>最新版本（见changelog.md）<span class="hljs-tag">&lt;/<span class="hljs-title">version</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-title">dependency</span>&gt;</span>
</code></pre>
<ul>
<li>假设数据库有张<code>t_user</code>表，添加对应的实体类<code>TUser.java</code>和Mapper<code>TUserMapper.java</code>(可用fastmybatis-generator来生成)</li>
<li>在<code>application.propertis</code>中配置数据库连接</li>
<li>编写测试用例</li>
</ul>
<pre><code class="hljs"><span class="hljs-annotation">@Autowired</span>
TUserMapper mapper;
    
<span class="hljs-comment">// 根据主键查询</span>
<span class="hljs-annotation">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">testGetById</span><span class="hljs-params">()</span> </span>{
    TUser user = mapper.getById(<span class="hljs-number">3</span>);
    System.out.println(user);
}
</code></pre>
<h1>查询</h1>
<p>本小节主要讲解fastmybatis的查询功能。fastmybatis提供丰富的查询方式，满足日常查询所需。</p>
<h2>分页查询</h2>
<h3>方式1</h3>
<p>前端传递两个分页参数pageIndex，pageSize</p>
<pre><code class="hljs">	<span class="hljs-comment">// http://localhost:8080/page1?pageIndex=1&amp;pageSize=10</span>
	@GetMapping(<span class="hljs-string">"page1"</span>)
	public <span class="hljs-keyword">List</span>&lt;TUser&gt; page1(int pageIndex,int pageSize) {
		<span class="hljs-keyword">Query</span> <span class="hljs-keyword">query</span> = new <span class="hljs-keyword">Query</span>();
		<span class="hljs-keyword">query</span>.page(pageIndex, pageSize);
		<span class="hljs-keyword">List</span>&lt;TUser&gt; <span class="hljs-keyword">list</span> = mapper.<span class="hljs-keyword">list</span>(<span class="hljs-keyword">query</span>);
		<span class="hljs-keyword">return</span> <span class="hljs-keyword">list</span>;
	}
</code></pre>
<h3>方式2</h3>
<p>PageParam里面封装了pageIndex，pageSize参数</p>
<pre><code class="hljs">	<span class="hljs-comment">// http://localhost:8080/page2?pageIndex=1&amp;pageSize=10</span>
	@GetMapping(<span class="hljs-string">"page2"</span>)
	public <span class="hljs-keyword">List</span>&lt;TUser&gt; page2(PageParam param) {
		<span class="hljs-keyword">Query</span> <span class="hljs-keyword">query</span> = param.toQuery();
		<span class="hljs-keyword">List</span>&lt;TUser&gt; <span class="hljs-keyword">list</span> = mapper.<span class="hljs-keyword">list</span>(<span class="hljs-keyword">query</span>);
		<span class="hljs-keyword">return</span> <span class="hljs-keyword">list</span>;
	}
</code></pre>
<h3>返回结果集和总记录数</h3>
<p>方式1和方式2只能查询结果集，通常我们查询还需返回记录总数并返回给前端，fastmybatis的处理方式如下：</p>
<pre><code class="hljs">// http://localhost:<span class="hljs-number">8080</span>/page3?pageIndex=<span class="hljs-number">1</span>&amp;pageSize=<span class="hljs-number">10</span>
	@<span class="hljs-type">GetMapping</span>(<span class="hljs-string">"page3"</span>)
	public <span class="hljs-type">Map</span>&lt;<span class="hljs-type">String</span>,<span class="hljs-type">Object</span>&gt; page3(<span class="hljs-type">PageParam</span> param) {
		<span class="hljs-type">Query</span> query = param.toQuery();
		<span class="hljs-type">List</span>&lt;<span class="hljs-type">TUser</span>&gt; list = mapper.list(query);
		long total = mapper.getCount(query);
		
		<span class="hljs-type">Map</span>&lt;<span class="hljs-type">String</span>,<span class="hljs-type">Object</span>&gt; <span class="hljs-literal">result</span> = new <span class="hljs-type">HashMap</span>&lt;<span class="hljs-type">String</span>, <span class="hljs-type">Object</span>&gt;();
		<span class="hljs-literal">result</span>.put(<span class="hljs-string">"list"</span>, list);
		<span class="hljs-literal">result</span>.put(<span class="hljs-string">"total"</span>, total);
		
		<span class="hljs-keyword">return</span> <span class="hljs-literal">result</span>;
	}
</code></pre>
<p>fastmybatis提供一种更简洁的方式来处理：</p>
<pre><code class="hljs">// http://localhost:<span class="hljs-number">8080</span>/page4?pageIndex=<span class="hljs-number">1</span>&amp;pageSize=<span class="hljs-number">10</span>
	@<span class="hljs-type">GetMapping</span>(<span class="hljs-string">"page4"</span>)
	public <span class="hljs-type">PageInfo</span>&lt;<span class="hljs-type">TUser</span>&gt; page4(<span class="hljs-type">PageParam</span> param) {
		<span class="hljs-type">PageInfo</span>&lt;<span class="hljs-type">TUser</span>&gt; pageInfo = <span class="hljs-type">MapperUtil</span>.query(mapper, query);
		<span class="hljs-keyword">return</span> <span class="hljs-literal">result</span>;
	}
</code></pre>
<p>PageInfo里面包含了List，total信息，还包含了一些额外信息，完整数据如下：</p>
<pre><code class="hljs">{
    <span class="hljs-string">"currentPageIndex"</span>: <span class="hljs-number">1</span>, <span class="hljs-comment">// 当前页</span>
    <span class="hljs-string">"firstPageIndex"</span>: <span class="hljs-number">1</span>, <span class="hljs-comment">// 首页</span>
    <span class="hljs-string">"lastPageIndex"</span>: <span class="hljs-number">2</span>, <span class="hljs-comment">// 尾页</span>
    <span class="hljs-string">"list"</span>: [     <span class="hljs-comment">// 结果集</span>
        {},
        {}
    ],
    <span class="hljs-string">"nextPageIndex"</span>: <span class="hljs-number">2</span>, <span class="hljs-comment">// 下一页</span>
    <span class="hljs-string">"pageCount"</span>: <span class="hljs-number">2</span>, <span class="hljs-comment">// 总页数</span>
    <span class="hljs-string">"pageIndex"</span>: <span class="hljs-number">1</span>, <span class="hljs-comment">// 当前页</span>
    <span class="hljs-string">"pageSize"</span>: <span class="hljs-number">10</span>, <span class="hljs-comment">// 每页记录数</span>
    <span class="hljs-string">"prePageIndex"</span>: <span class="hljs-number">1</span>, <span class="hljs-comment">// 上一页</span>
    <span class="hljs-string">"start"</span>: <span class="hljs-number">0</span>,
    <span class="hljs-string">"total"</span>: <span class="hljs-number">20</span> <span class="hljs-comment">// 总记录数</span>
}
</code></pre>
<h2>根据参数字段查询</h2>
<h3>查询姓名为张三的用户</h3>
<pre><code class="hljs"><span class="hljs-comment">// http://localhost:8080/sch?username=张三</span>
	@GetMapping(<span class="hljs-string">"sch"</span>)
	public <span class="hljs-keyword">List</span>&lt;TUser&gt; sch(String username) {
		<span class="hljs-keyword">Query</span> <span class="hljs-keyword">query</span> = new <span class="hljs-keyword">Query</span>();
		<span class="hljs-keyword">query</span>.<span class="hljs-keyword">eq</span>(<span class="hljs-string">"username"</span>, username);
		<span class="hljs-keyword">List</span>&lt;TUser&gt; <span class="hljs-keyword">list</span> = mapper.<span class="hljs-keyword">list</span>(<span class="hljs-keyword">query</span>);
		<span class="hljs-keyword">return</span> <span class="hljs-keyword">list</span>;
	}
</code></pre>
<h3>查询姓名为张三并且拥有的钱大于100块</h3>
<pre><code class="hljs"><span class="hljs-comment">// http://localhost:8080/sch2?username=张三</span>
	@GetMapping(<span class="hljs-string">"sch2"</span>)
	public <span class="hljs-keyword">List</span>&lt;TUser&gt; sch2(String username) {
		<span class="hljs-keyword">Query</span> <span class="hljs-keyword">query</span> = new <span class="hljs-keyword">Query</span>();
		<span class="hljs-keyword">query</span>.<span class="hljs-keyword">eq</span>(<span class="hljs-string">"username"</span>, username).gt(<span class="hljs-string">"money"</span>, 100);
		<span class="hljs-keyword">List</span>&lt;TUser&gt; <span class="hljs-keyword">list</span> = mapper.<span class="hljs-keyword">list</span>(<span class="hljs-keyword">query</span>);
		<span class="hljs-keyword">return</span> <span class="hljs-keyword">list</span>;
	}
</code></pre>
<h3>查询姓名为张三并带分页</h3>
<pre><code class="hljs"><span class="hljs-comment">// http://localhost:8080/sch3?username=张三&amp;pageIndex=1&amp;pageSize=5</span>
	@GetMapping(<span class="hljs-string">"sch3"</span>)
	public <span class="hljs-keyword">List</span>&lt;TUser&gt; sch3(String username,PageParam param) {
		<span class="hljs-keyword">Query</span> <span class="hljs-keyword">query</span> = param.toQuery();
		<span class="hljs-keyword">query</span>.<span class="hljs-keyword">eq</span>(<span class="hljs-string">"username"</span>, username);
		<span class="hljs-keyword">List</span>&lt;TUser&gt; <span class="hljs-keyword">list</span> = mapper.<span class="hljs-keyword">list</span>(<span class="hljs-keyword">query</span>);
		<span class="hljs-keyword">return</span> <span class="hljs-keyword">list</span>;
	}
</code></pre>
<h3>查询钱最多的前三名</h3>
<pre><code class="hljs"><span class="hljs-comment">// http://localhost:8080/sch4</span>
	@GetMapping(<span class="hljs-string">"sch4"</span>)
	public <span class="hljs-keyword">List</span>&lt;TUser&gt; sch4() {
		<span class="hljs-keyword">Query</span> <span class="hljs-keyword">query</span> = new <span class="hljs-keyword">Query</span>();
		<span class="hljs-keyword">query</span>.orderby(<span class="hljs-string">"money"</span>, <span class="hljs-keyword">Sort</span>.<span class="hljs-keyword">DESC</span>) <span class="hljs-comment">// 按金额降序</span>
			.page(1, 3);
		<span class="hljs-keyword">List</span>&lt;TUser&gt; <span class="hljs-keyword">list</span> = mapper.<span class="hljs-keyword">list</span>(<span class="hljs-keyword">query</span>);
		<span class="hljs-keyword">return</span> <span class="hljs-keyword">list</span>;
	}
</code></pre>
<h3>将参数放在对象中查询</h3>
<pre><code class="hljs"><span class="hljs-comment">// http://localhost:8080/sch5?username=张三</span>
	@GetMapping(<span class="hljs-string">"sch5"</span>)
	public <span class="hljs-keyword">List</span>&lt;TUser&gt; sch5(UserParam userParam) {
		<span class="hljs-keyword">Query</span> <span class="hljs-keyword">query</span> = userParam.toQuery();
		<span class="hljs-keyword">query</span>.<span class="hljs-keyword">eq</span>(<span class="hljs-string">"username"</span>, userParam.getUsername());
		<span class="hljs-keyword">List</span>&lt;TUser&gt; <span class="hljs-keyword">list</span> = mapper.<span class="hljs-keyword">list</span>(<span class="hljs-keyword">query</span>);
		<span class="hljs-keyword">return</span> <span class="hljs-keyword">list</span>;
	}
</code></pre>
<p>UserParam继承PageSortParam类，表示支持分页和排序查询</p>
<h3>使用普通bean查询</h3>
<p>假设有个User类如下</p>
<pre><code class="hljs"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">User</span> {
	<span class="hljs-keyword">private</span> Integer id;
	<span class="hljs-keyword">private</span> String userName;

	<span class="hljs-function"><span class="hljs-keyword">public</span> Integer <span class="hljs-title">getId</span><span class="hljs-params">()</span> </span>{
		<span class="hljs-keyword">return</span> id;
	}

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setId</span><span class="hljs-params">(Integer id)</span> </span>{
		<span class="hljs-keyword">this</span>.id = id;
	}

	<span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getUserName</span><span class="hljs-params">()</span> </span>{
		<span class="hljs-keyword">return</span> userName;
	}

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setUserName</span><span class="hljs-params">(String userName)</span> </span>{
		<span class="hljs-keyword">this</span>.userName = userName;
	}
}
</code></pre>
<p>我们将这个类作为查询参数,那么在springmvc中可以这样写:</p>
<pre><code class="hljs">@GetMapping(path=<span class="hljs-string">"findUserBean.do"</span>)
public <span class="hljs-keyword">List</span>&lt;User&gt; findUser(User user) {
	<span class="hljs-keyword">Query</span> <span class="hljs-keyword">query</span> = <span class="hljs-keyword">Query</span>.build(user);
	<span class="hljs-keyword">List</span>&lt;User&gt; <span class="hljs-keyword">list</span> = dao.find(<span class="hljs-keyword">query</span>);
	<span class="hljs-keyword">return</span> <span class="hljs-keyword">list</span>;
}
</code></pre>
<p>Query query = Query.build(user);这句是将User中的属性转换成对应条件,假设userName的值为"jim",那么会封装成一个条件where user_name=‘jim’</p>
<p>浏览器输入链接:<a href="http://localhost:8080/fastmybatis-springmvc/findUserBean.do?userName=jim">http://localhost:8080/fastmybatis-springmvc/findUserBean.do?userName=jim</a>
后台将会执行如下SQL:</p>
<pre><code class="hljs"><span class="hljs-operator"><span class="hljs-keyword">SELECT</span> id,user_name <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">user</span> t <span class="hljs-keyword">WHERE</span> t.user_name = ?
</span></code></pre>
<p>?的值为jim</p>
<h3>@Condition注解</h3>
<p>@Condition注解用来强化查询，有了这个注解可以生成各种查询条件。</p>
<p>@Condition注解有三个属性：</p>
<ul>
<li>joint：表达式之间的连接符,AND|OR,默认AND</li>
<li>column：数据库字段名，可选</li>
<li>operator：连接符枚举，存放了等于、大于、小于等连接符</li>
</ul>
<p>如果要查询id大于2的用户只需在get方法上加上一个@Condition注解即可:</p>
<pre><code class="hljs"><span class="hljs-annotation">@Condition</span>(operator=Operator.gt)
<span class="hljs-keyword">public</span> <span class="hljs-function">Integer <span class="hljs-title">getId</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.id;
}
</code></pre>
<p>这样，当id有值时，会封装成一个<strong>where id&gt;2</strong>的条件</p>
<ul>
<li>需要注意的是，如果不指定column属性，系统会默认取get方法中属性名，然后转换成数据库字段名。如果需要指定数据库字段名的话，可以使用@Condition的column属性。</li>
</ul>
<p>public Integer get++UserName++() {
return this.userName;
}</p>
<p>这种情况下会取下划线部分字段，然后转换成数据库字段名。</p>
<pre><code class="hljs"><span class="hljs-annotation">@Condition</span>(column=<span class="hljs-string">"username"</span>) <span class="hljs-comment">// 显示指定字段名</span>
<span class="hljs-keyword">public</span> <span class="hljs-function">Integer <span class="hljs-title">getUserName</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.userName;
}
</code></pre>
<p>使用@Condition可以生产更加灵活的条件查询,比如需要查询日期为2017-12-1~2017-12-10日的记录,我们可以这样写:</p>
<pre><code class="hljs"><span class="hljs-annotation">@Condition</span>(column=<span class="hljs-string">"add_date"</span>,operator=Operator.ge)
<span class="hljs-keyword">public</span> <span class="hljs-function">Date <span class="hljs-title">getStartDate</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.startDate;
}

<span class="hljs-annotation">@Condition</span>(column=<span class="hljs-string">"add_date"</span>,operator=Operator.lt)
<span class="hljs-keyword">public</span> <span class="hljs-function">Date <span class="hljs-title">getEndDate</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.endDate;
}
</code></pre>
<p>转换成SQL语句:</p>
<pre><code class="hljs">t.add_date&gt;=<span class="hljs-string">'2017-12-1'</span> <span class="hljs-keyword">AND</span> t.add_date&lt;<span class="hljs-string">'2017-12-10'</span>
</code></pre>
<h4>忽略空字符串（v1.0.16）</h4>
<p>1.0.16版本中，@Condition注解新增一个<code>ignoreEmptyString</code>属性，默认是false。如果设置true，则忽略空字符串的字段，即空字符串的字段不会加入到条件当中。</p>
<pre><code class="hljs"><span class="hljs-annotation">@Condition</span>(ignoreEmptyString = <span class="hljs-keyword">true</span>)
<span class="hljs-keyword">public</span> <span class="hljs-function">String <span class="hljs-title">getChannelId</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-keyword">return</span> channelId;
}    
</code></pre>
<p>如果channelId是""(空字符串)，该字段不会加入到条件当中。</p>
<h4>IN查询</h4>
<p>假设前端页面传来多个值比如checkbox勾选多个id=[1,2],那么我们在User类里面可以用Integer[]或List&lt;Integer&gt;来接收.</p>
<pre><code class="hljs"><span class="hljs-keyword">private</span> Integer[] idArr;

<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">setIdArr</span><span class="hljs-params">(Integer[] idArr)</span> </span>{<span class="hljs-keyword">this</span>.idArr = idArr;}

<span class="hljs-annotation">@Condition</span>(column=<span class="hljs-string">"id"</span>)
<span class="hljs-keyword">public</span> Integer[] getIdArr() {<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.idArr;}
</code></pre>
<p>这样会生成where id IN(1,2)条件。</p>
<h2>排序查询</h2>
<p>// 根据添加时间倒序</p>
<pre><code class="hljs"><span class="hljs-keyword">Query</span> <span class="hljs-keyword">query</span> = new <span class="hljs-keyword">Query</span>();
<span class="hljs-keyword">query</span>.orderby(<span class="hljs-string">"create_time"</span>,<span class="hljs-keyword">Sort</span>.<span class="hljs-keyword">DESC</span>);
dao.find(<span class="hljs-keyword">query</span>);
</code></pre>
<h2>多表关联查询</h2>
<p>多表关联查询使用的地方很多，比如需要关联第二张表，获取第二张表的几个字段，然后返回给前端。</p>
<p>fastmybatis的用法如下：</p>
<p>假如我们需要关联第二张表<code>user_info</code>，筛选出user_info中的城市为杭州的数据。</p>
<pre><code class="hljs"><span class="hljs-keyword">Query</span> <span class="hljs-keyword">query</span> = new <span class="hljs-keyword">Query</span>()
        <span class="hljs-comment">// 左连接查询,主表的alias默认为t</span>
        .join(<span class="hljs-string">"LEFT JOIN user_info t2 ON t.id = t2.user_id"</span>).page(1, 5)
        .<span class="hljs-keyword">eq</span>(<span class="hljs-string">"t2.city"</span>,<span class="hljs-string">"杭州"</span>);

<span class="hljs-keyword">List</span>&lt;TUser&gt; <span class="hljs-keyword">list</span> = mapper.<span class="hljs-keyword">list</span>(<span class="hljs-keyword">query</span>);

System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"=============="</span>);
<span class="hljs-keyword">for</span> (TUser user : <span class="hljs-keyword">list</span>) {
    System.<span class="hljs-keyword">out</span>.println(user.getId() + <span class="hljs-string">" "</span> + user.getUsername());
}
System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"=============="</span>);
</code></pre>
<h3>多表关联返回指定字段</h3>
<p>有时候不需要全部字段，需要取表1中的几个字段，然后取表2中的几个字段，fastmybatis实现方式如下：</p>
<pre><code class="hljs"><span class="hljs-keyword">Query</span> <span class="hljs-keyword">query</span> = new <span class="hljs-keyword">Query</span>();
<span class="hljs-comment">// 左连接查询,主表的alias默认为t</span>
<span class="hljs-keyword">query</span>.join(<span class="hljs-string">"LEFT JOIN user_info t2 ON t.id = t2.user_id"</span>);
<span class="hljs-comment">// 指定返回字段</span>
<span class="hljs-keyword">List</span>&lt;String&gt; column = Arrays.asList(<span class="hljs-string">"t2.user_id as userId"</span>, <span class="hljs-string">"t.username"</span>, <span class="hljs-string">"t2.city"</span>);
<span class="hljs-comment">// 查询结果返回到map中</span>
<span class="hljs-keyword">List</span>&lt;Map&lt;String, Object&gt;&gt; mapList = mapper.listMap(column, <span class="hljs-keyword">query</span>);
<span class="hljs-comment">// 再将map转换成实体bean</span>
<span class="hljs-keyword">List</span>&lt;UserInfoVo&gt; <span class="hljs-keyword">list</span> = MyBeanUtil.mapListToObjList(mapList, UserInfoVo.<span class="hljs-keyword">class</span>);
</code></pre>
<p>执行的SQL语句对应如下：</p>
<pre><code class="hljs">SELECT t2<span class="hljs-class">.user_id</span> as userId , t<span class="hljs-class">.username</span> , t2<span class="hljs-class">.city</span>
FROM `t_user` t 
LEFT JOIN user_info t2 ON t<span class="hljs-class">.id</span> = t2<span class="hljs-class">.user_id</span>
</code></pre>
<h2>使用@Select查询</h2>
<p>@Select注解是mybatis官方提供的一个功能，fastmybatis可以理解为是官方的一种扩展，因此同样支持此功能。
在Mapper中添加如下代码：</p>
<pre><code class="hljs"><span class="hljs-variable">@Select</span>(<span class="hljs-string">"select * from t_user where id=#{id}"</span>)
TUser <span class="hljs-function">selectById</span>(<span class="hljs-variable">@Param</span>(<span class="hljs-string">"id"</span>) int id);
</code></pre>
<p>编写测试用例</p>
<pre><code class="hljs"><span class="hljs-annotation">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">testSelectById</span><span class="hljs-params">()</span> </span>{
    TUser user = dao.selectById(<span class="hljs-number">3</span>);

    System.out.println(user.getUsername());
}
</code></pre>
<p>对于简单的SQL，可以用这种方式实现。除了@Select之外，还有@Update，@Insert，@Delete，这里就不多做演示了。</p>
<h2>Query类详解</h2>
<p>Query是一个查询参数类，配合Mapper一起使用。</p>
<h3>参数介绍</h3>
<p>Query里面封装了一系列查询参数，主要分为以下几类：</p>
<ul>
<li>分页参数：设置分页</li>
<li>排序参数：设置排序字段</li>
<li>条件参数：设置查询条件</li>
<li>字段参数：可返回指定字段</li>
</ul>
<p>下面逐个讲解每个参数的用法。</p>
<h3>分页参数</h3>
<p>一般来说分页的使用比较简单，通常是两个参数，
pageIndex：当前页索引，pageSize：每页几条数据。
Query类使用**page(pageIdnex, pageSize)**方法来设置。
假如我们要查询第二页，每页10条数据，代码可以这样写：</p>
<pre><code class="hljs"><span class="hljs-keyword">Query</span> <span class="hljs-keyword">query</span> = new <span class="hljs-keyword">Query</span>();
<span class="hljs-keyword">query</span>.page(2, 10);
<span class="hljs-keyword">List</span>&lt;User&gt; <span class="hljs-keyword">list</span> = dao.find(<span class="hljs-keyword">query</span>);
</code></pre>
<p>如果要实现不规则分页，可以这样写：</p>
<pre><code class="hljs"><span class="hljs-keyword">Query</span> <span class="hljs-keyword">query</span> = new <span class="hljs-keyword">Query</span>();
<span class="hljs-keyword">query</span>.limit(3, 5) <span class="hljs-comment">// 对应mysql：limit 3,5</span>
</code></pre>
<h3>排序参数</h3>
<pre><code class="hljs"><span class="hljs-function"><span class="hljs-title">orderby</span><span class="hljs-params">(String sortname, Sort sort)</span></span>
</code></pre>
<p>其中sortname为数据库字段，非javaBean属性</p>
<ul>
<li>orderby(String sortname, Sort sort)则可以指定排序方式，Sort为排序方式枚举
假如要按照添加时间倒序，可以这样写：</li>
</ul>
<pre><code class="hljs"><span class="hljs-keyword">Query</span> <span class="hljs-keyword">query</span> = new <span class="hljs-keyword">Query</span>();
<span class="hljs-keyword">query</span>.orderby(<span class="hljs-string">"create_time"</span>,<span class="hljs-keyword">Sort</span>.<span class="hljs-keyword">DESC</span>);
mapper.<span class="hljs-keyword">list</span>(<span class="hljs-keyword">query</span>);
</code></pre>
<p>添加多个排序字段可以在后面追加：</p>
<pre><code class="hljs"><span class="hljs-keyword">query</span>.orderby(<span class="hljs-string">"create_time"</span>,<span class="hljs-keyword">Sort</span>.<span class="hljs-keyword">DESC</span>).orderby(<span class="hljs-string">"id"</span>,<span class="hljs-keyword">Sort</span>.ASC);
</code></pre>
<h3>条件参数</h3>
<p>条件参数是用的最多一个，因为在查询中往往需要加入各种条件。
fastmybatis在条件查询上面做了一些封装，这里不做太多讲解，只讲下基本的用法，以后会单独开一篇文章来介绍。感兴趣的同学可以自行查看源码，也不难理解。</p>
<p>条件参数使用非常简单，Query对象封装一系列常用条件查询。</p>
<ul>
<li>等值查询eq(String columnName, Object value)，columnName为数据库字段名，value为查询的值
假设我们要查询姓名为张三的用户，可以这样写：</li>
</ul>
<pre><code class="hljs"><span class="hljs-keyword">Query</span> <span class="hljs-keyword">query</span> = new <span class="hljs-keyword">Query</span>();
<span class="hljs-keyword">query</span>.<span class="hljs-keyword">eq</span>(<span class="hljs-string">"username"</span>,<span class="hljs-string">"张三"</span>);
<span class="hljs-keyword">List</span>&lt;User&gt; <span class="hljs-keyword">list</span> = mapper.<span class="hljs-keyword">list</span>(<span class="hljs-keyword">query</span>);
</code></pre>
<p>通过方法名即可知道eq表示等于’=’，同理lt表示小于&lt;,gt表示大于&gt;</p>
<table>
<thead>
<tr>
<th>查询方式</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>eq</td>
<td>等于=</td>
</tr>
<tr>
<td>gt</td>
<td>大于&gt;</td>
</tr>
<tr>
<td>lt</td>
<td>小于&lt;</td>
</tr>
<tr>
<td>ge</td>
<td>大于等于&gt;=</td>
</tr>
<tr>
<td>le</td>
<td>小于等于&lt;=</td>
</tr>
<tr>
<td>notEq</td>
<td>不等于&lt;&gt;</td>
</tr>
<tr>
<td>like</td>
<td>模糊查询</td>
</tr>
<tr>
<td>in</td>
<td>in()查询</td>
</tr>
<tr>
<td>notIn</td>
<td>not in()查询</td>
</tr>
<tr>
<td>isNull</td>
<td>NULL值查询</td>
</tr>
<tr>
<td>notNull</td>
<td>IS NOT NULL</td>
</tr>
<tr>
<td>notEmpty</td>
<td>字段不为空，非NULL且有内容</td>
</tr>
<tr>
<td>isEmpty</td>
<td>字段为NULL或者为’’</td>
</tr>
</tbody>
</table>
<p>如果上述方法还不能满足查询需求的话，我们可以使用自定sql的方式来编写查询条件，方法为：</p>
<pre><code class="hljs"><span class="hljs-keyword">Query</span> <span class="hljs-keyword">query</span> = new <span class="hljs-keyword">Query</span>();
<span class="hljs-keyword">query</span>.sql(<span class="hljs-string">" username='Jim' OR username='Tom'"</span>);
</code></pre>
<p><strong>注意</strong>：sql()方法不会处理sql注入问题，因此尽量少用。</p>
<h1>自定义SQL</h1>
<h2>方式1</h2>
<p>直接写在Mapper.java中</p>
<pre><code class="hljs"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">TUserMapper</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">CrudMapper</span>&lt;<span class="hljs-title">TUser</span>, <span class="hljs-title">Integer</span>&gt; {</span>

    <span class="hljs-comment">// 自定义sql，官方自带，不需要写xml</span>
    <span class="hljs-javadoc">/**
     * 修改用户名
     *<span class="hljs-javadoctag"> @param</span> id
     *<span class="hljs-javadoctag"> @param</span> username
     *<span class="hljs-javadoctag"> @return</span> 返回影响行数
     */</span>
    <span class="hljs-annotation">@Update</span>(<span class="hljs-string">"update t_user set username = #{username} where id = #{id}"</span>)
    <span class="hljs-typename">int</span> updateById(<span class="hljs-annotation">@Param</span>(<span class="hljs-string">"id"</span>) <span class="hljs-typename">int</span> id, <span class="hljs-annotation">@Param</span>(<span class="hljs-string">"username"</span>) String username);
 
}
</code></pre>
<p>简单SQL可采用这种形式。</p>
<h2>方式2</h2>
<p>fastmybatis提供的Mapper已经满足大部分的操作需求，但是有些复杂的sql语句还是需要写在xml文件中。fastmybatis同样支持将sql语句写在xml中，具体配置如下：</p>
<ul>
<li>在application.properties添加一句，指定xml文件存放路径</li>
</ul>
<pre><code class="hljs">mybatis.mapper-locations=<span class="hljs-keyword">classpath</span>:<span class="hljs-regexp">/mybatis/m</span>apper<span class="hljs-comment">/*.xml
</span></code></pre>
<ul>
<li>在resources/mybatis/mapper目录下新建一个xml文件TUserMapper.xml，内容如下：</li>
</ul>
<pre><code class="hljs"><span class="hljs-pi">&lt;?xml version="1.0" encoding="utf-8"?&gt;</span>
<span class="hljs-doctype">&lt;!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-title">mapper</span> <span class="hljs-attribute">namespace</span>=<span class="hljs-value">"com.mayapp.mapper.TUserMapper"</span>&gt;</span>
	
	<span class="hljs-tag">&lt;<span class="hljs-title">select</span> <span class="hljs-attribute">id</span>=<span class="hljs-value">"selectByName"</span> <span class="hljs-attribute">parameterType</span>=<span class="hljs-value">"String"</span> <span class="hljs-attribute">resultMap</span>=<span class="hljs-value">"baseResultMap"</span>&gt;</span>
		select * from t_user t where t.username = #{username} limit 1
	<span class="hljs-tag">&lt;/<span class="hljs-title">select</span>&gt;</span>
	
<span class="hljs-tag">&lt;/<span class="hljs-title">mapper</span>&gt;</span>
</code></pre>
<p>这个xml文件跟其它的mybatis配置文件一样，baseResultMap没有看到定义，但是确实存在，因为这个是fastmybatis提供的一个内置resultMap。</p>
<ul>
<li>在TUseroMapper.java中添加：</li>
</ul>
<pre><code class="hljs"><span class="hljs-function">TUser <span class="hljs-title">selectByName</span><span class="hljs-params">(@Param(<span class="hljs-string">"username"</span>)</span>String username)</span>;
</code></pre>
<ul>
<li>编写单元测试用例</li>
</ul>
<pre><code class="hljs"><span class="hljs-annotation">@Test</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">testSelectByName</span><span class="hljs-params">()</span> </span>{
    TUser user = dao.selectByName(<span class="hljs-string">"张三"</span>);

    System.out.println(user.getUsername());
}
    
</code></pre>
<h3>多文件同一个namespace</h3>
<p>在以往的开发过程中，一个Mapper对应一个xml文件（namespace）。如果多人同时在一个xml中写SQL的话会造成各种冲突（虽然能够最终被解决）。</p>
<p>fastmybatis打破这种常规，允许不同的xml文件定义相同的namespace，程序启动时会自动把他们的内容合并到同一个文件当中去。</p>
<ul>
<li>张三的UserMapper_zs.xml</li>
</ul>
<pre><code class="hljs"><span class="hljs-pi">&lt;?xml version="1.0" encoding="utf-8"?&gt;</span>
<span class="hljs-doctype">&lt;!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-title">mapper</span> <span class="hljs-attribute">namespace</span>=<span class="hljs-value">"com.mayapp.mapper.TUserMapper"</span>&gt;</span>
	
	<span class="hljs-tag">&lt;<span class="hljs-title">select</span> <span class="hljs-attribute">id</span>=<span class="hljs-value">"selectByName"</span> <span class="hljs-attribute">parameterType</span>=<span class="hljs-value">"String"</span> <span class="hljs-attribute">resultMap</span>=<span class="hljs-value">"baseResultMap"</span>&gt;</span>
		select * from t_user t where t.username = #{username} limit 1
	<span class="hljs-tag">&lt;/<span class="hljs-title">select</span>&gt;</span>
	
<span class="hljs-tag">&lt;/<span class="hljs-title">mapper</span>&gt;</span>
</code></pre>
<ul>
<li>李四的UserMapper_ls.xml</li>
</ul>
<pre><code class="hljs"><span class="hljs-pi">&lt;?xml version="1.0" encoding="utf-8"?&gt;</span>
<span class="hljs-doctype">&lt;!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-title">mapper</span> <span class="hljs-attribute">namespace</span>=<span class="hljs-value">"com.mayapp.mapper.TUserMapper"</span>&gt;</span>
	
	<span class="hljs-tag">&lt;<span class="hljs-title">select</span> <span class="hljs-attribute">id</span>=<span class="hljs-value">"updateUser"</span> <span class="hljs-attribute">parameterType</span>=<span class="hljs-value">"String"</span> <span class="hljs-attribute">resultMap</span>=<span class="hljs-value">"baseResultMap"</span>&gt;</span>
		update t_user set username = #{username} where id=#{id}
	<span class="hljs-tag">&lt;/<span class="hljs-title">select</span>&gt;</span>
	
<span class="hljs-tag">&lt;/<span class="hljs-title">mapper</span>&gt;</span>
</code></pre>
<p>最终会合并成</p>
<pre><code class="hljs"><span class="hljs-pi">&lt;?xml version="1.0" encoding="utf-8"?&gt;</span>
<span class="hljs-doctype">&lt;!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-title">mapper</span> <span class="hljs-attribute">namespace</span>=<span class="hljs-value">"com.mayapp.mapper.TUserMapper"</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- 张三部分 --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-title">select</span> <span class="hljs-attribute">id</span>=<span class="hljs-value">"selectByName"</span> <span class="hljs-attribute">parameterType</span>=<span class="hljs-value">"String"</span> <span class="hljs-attribute">resultMap</span>=<span class="hljs-value">"baseResultMap"</span>&gt;</span>
		select * from t_user t where t.username = #{username} limit 1
	<span class="hljs-tag">&lt;/<span class="hljs-title">select</span>&gt;</span>
	
	<span class="hljs-comment">&lt;!-- 李四部分 --&gt;</span>
	<span class="hljs-tag">&lt;<span class="hljs-title">select</span> <span class="hljs-attribute">id</span>=<span class="hljs-value">"updateUser"</span> <span class="hljs-attribute">parameterType</span>=<span class="hljs-value">"String"</span> <span class="hljs-attribute">resultMap</span>=<span class="hljs-value">"baseResultMap"</span>&gt;</span>
		update t_user set username = #{username} where id=#{id}
	<span class="hljs-tag">&lt;/<span class="hljs-title">select</span>&gt;</span>
	
<span class="hljs-tag">&lt;/<span class="hljs-title">mapper</span>&gt;</span>
</code></pre>
<p>这样也体现了开闭原则，即新增一个功能只需要新增一个文件就行，不需要修改原来的文件。</p>
<p>如果SQL写多了还可以把它们进行分类，放到不同的xml中，便于管理。</p>
<p>**注：**合并动作是在启动时进行的，并不会生成一个真实的文件。</p>
<h1>字段自动填充</h1>
<h2>填充器设置</h2>
<p>假设数据库表里面有两个时间字段gmt_create,gmt_update。</p>
<p>当进行insert操作时gmt_create，gmt_update字段需要更新。当update时，gmt_update字段需要更新。</p>
<p>通常的做法是通过Entity手动设置：</p>
<pre><code class="hljs"><span class="hljs-built_in">User</span> <span class="hljs-built_in">user</span> = new <span class="hljs-built_in">User</span>();
<span class="hljs-built_ins">user</span>.setGmtCreate(new Date());
<span class="hljs-built_ins">user</span>.setGmtUpdate(new Date());
</code></pre>
<p>因为表设计的时候大部分都有这两个字段，所以对每张表都进行手动设置的话很容易错加、漏加。
fastmybatis提供了两个辅助类DateFillInsert和DateFillUpdate，用来处理添加修改时的时间字段自动填充。配置了这两个类之后，时间字段将会自动设置。</p>
<p>配置方式如下：</p>
<pre><code class="hljs"><span class="hljs-type">FastmybatisConfig</span> config = <span class="hljs-keyword">new</span> <span class="hljs-type">FastmybatisConfig</span><span class="hljs-literal">()</span>;

    config.setFills(<span class="hljs-type">Arrays</span>.asList(
			<span class="hljs-keyword">new</span> <span class="hljs-type">DateFillInsert</span><span class="hljs-literal">()</span>
			,<span class="hljs-keyword">new</span> <span class="hljs-type">DateFillUpdate</span><span class="hljs-literal">()</span>
			));
</code></pre>
<p>在spring的xml中配置如下:</p>
<pre><code class="hljs"><span class="hljs-tag">&lt;<span class="hljs-title">bean</span> <span class="hljs-attribute">id</span>=<span class="hljs-value">"sqlSessionFactory"</span>
		<span class="hljs-attribute">class</span>=<span class="hljs-value">"com.gitee.fastmybatis.core.ext.SqlSessionFactoryBeanExt"</span>&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-title">property</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"dataSource"</span> <span class="hljs-attribute">ref</span>=<span class="hljs-value">"dataSource"</span> /&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-title">property</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"configLocation"</span>&gt;</span>
			<span class="hljs-tag">&lt;<span class="hljs-title">value</span>&gt;</span>classpath:mybatis/mybatisConfig.xml<span class="hljs-tag">&lt;/<span class="hljs-title">value</span>&gt;</span>
		<span class="hljs-tag">&lt;/<span class="hljs-title">property</span>&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-title">property</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"mapperLocations"</span>&gt;</span>
			<span class="hljs-tag">&lt;<span class="hljs-title">list</span>&gt;</span>
				<span class="hljs-tag">&lt;<span class="hljs-title">value</span>&gt;</span>classpath:mybatis/mapper/*.xml<span class="hljs-tag">&lt;/<span class="hljs-title">value</span>&gt;</span>
			<span class="hljs-tag">&lt;/<span class="hljs-title">list</span>&gt;</span>
		<span class="hljs-tag">&lt;/<span class="hljs-title">property</span>&gt;</span>
		
		<span class="hljs-comment">&lt;!-- 以下是附加属性 --&gt;</span>
		
		<span class="hljs-comment">&lt;!-- dao所在的包名,跟MapperScannerConfigurer的basePackage一致 
			多个用;隔开
		--&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-title">property</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"basePackage"</span> <span class="hljs-attribute">value</span>=<span class="hljs-value">"com.myapp.dao"</span> /&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-title">property</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"config"</span>&gt;</span>
			<span class="hljs-tag">&lt;<span class="hljs-title">bean</span> <span class="hljs-attribute">class</span>=<span class="hljs-value">"com.gitee.fastmybatis.core.FastmybatisConfig"</span>&gt;</span>
                                <span class="hljs-comment">&lt;!-- 定义填充器 --&gt;</span>
				<span class="hljs-tag">&lt;<span class="hljs-title">property</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"fills"</span>&gt;</span>
					<span class="hljs-tag">&lt;<span class="hljs-title">list</span>&gt;</span>
                                        <span class="hljs-tag">&lt;<span class="hljs-title">bean</span> <span class="hljs-attribute">class</span>=<span class="hljs-value">"com.gitee.fastmybatis.core.support.DateFillInsert"</span>/&gt;</span>
                                        <span class="hljs-tag">&lt;<span class="hljs-title">bean</span> <span class="hljs-attribute">class</span>=<span class="hljs-value">"com.gitee.fastmybatis.core.support.DateFillUpdate"</span>/&gt;</span>
					<span class="hljs-tag">&lt;/<span class="hljs-title">list</span>&gt;</span>
				<span class="hljs-tag">&lt;/<span class="hljs-title">property</span>&gt;</span>
			<span class="hljs-tag">&lt;/<span class="hljs-title">bean</span>&gt;</span>
		<span class="hljs-tag">&lt;/<span class="hljs-title">property</span>&gt;</span>
	<span class="hljs-tag">&lt;/<span class="hljs-title">bean</span>&gt;</span>
</code></pre>
<p>springboot中可以这样定义:</p>
<p>在application.properties中添加：</p>
<pre><code class="hljs">mybatis<span class="hljs-class">.fill</span><span class="hljs-class">.com</span><span class="hljs-class">.gitee</span><span class="hljs-class">.fastmybatis</span><span class="hljs-class">.core</span><span class="hljs-class">.support</span><span class="hljs-class">.DateFillInsert</span>=
mybatis<span class="hljs-class">.fill</span><span class="hljs-class">.com</span><span class="hljs-class">.gitee</span><span class="hljs-class">.fastmybatis</span><span class="hljs-class">.core</span><span class="hljs-class">.support</span><span class="hljs-class">.DateFillUpdate</span>=
</code></pre>
<p>如果要指定字段名，可以写成：</p>
<pre><code class="hljs">mybatis<span class="hljs-class">.fill</span><span class="hljs-class">.com</span><span class="hljs-class">.gitee</span><span class="hljs-class">.fastmybatis</span><span class="hljs-class">.core</span><span class="hljs-class">.support</span><span class="hljs-class">.DateFillInsert</span>=create_time
</code></pre>
<h2>自定义填充器</h2>
<p>除了使用fastmybatis默认提供的填充之外，我们还可以自定义填充。</p>
<p>自定义填充类要继承BaseFill&lt;T&gt;类。
&lt;T&gt; 表示填充字段类型，如Date，String，BigDecimal，Boolean。</p>
<h3>实战(springboot)</h3>
<p>现在有个remark字段，需要在insert时初始化为“备注默认内容”，新建一个StringRemarkFill类如下：</p>
<pre><code class="hljs">public <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StringRemarkFill</span> <span class="hljs-keyword"><span class="hljs-keyword">extends</span></span> <span class="hljs-title">BaseFill&lt;String&gt;</span> {</span>

	<span class="hljs-annotation">@Override</span>
	public <span class="hljs-type">String</span> getColumnName() {
		<span class="hljs-keyword">return</span> <span class="hljs-string">"remark"</span>;
	}

	<span class="hljs-annotation">@Override</span>
	public <span class="hljs-type">FillType</span> getFillType() {
		<span class="hljs-keyword">return</span> <span class="hljs-type">FillType</span>.<span class="hljs-type">INSERT</span>;
	}

	<span class="hljs-annotation">@Override</span>
	<span class="hljs-keyword">protected</span> <span class="hljs-type">Object</span> getFillValue(<span class="hljs-type">String</span> defaultValue) {
		<span class="hljs-keyword">return</span> <span class="hljs-string">"备注默认内容"</span>;
	}

}
</code></pre>
<p>StringRemarkFill类中有三个重写方法：</p>
<ul>
<li>getColumnName() ： 指定表字段名</li>
<li>getFillType() ： 填充方式，FillType.INSERT:仅insert时填充； FillType.UPDATE：insert，update时填充</li>
<li>getFillValue(String defaultValue) ：返回填充内容</li>
</ul>
<p>然后在application.properties中添加：</p>
<pre><code class="hljs">mybatis<span class="hljs-class">.fill</span><span class="hljs-class">.com</span><span class="hljs-class">.xx</span><span class="hljs-class">.StringRemarkFill</span>=
</code></pre>
<p>这样就配置完毕了，调用dao.save(user);时会自动填充remark字段。</p>
<h2>指定目标类</h2>
<p>上面说到StringRemarkFill填充器，它作用在所有实体类上，也就是说实体类如果有remark字段都会自动填充。这样显然是不合理的，解决办法是指定特定的实体类。只要重写BaseFill类的getTargetEntityClasses()方法即可。</p>
<pre><code class="hljs">@Override
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">Class</span>&lt;?&gt;[] <span class="hljs-title">getTargetEntityClasses</span>() {</span>
	<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-class"><span class="hljs-keyword">Class</span>&lt;?&gt;[] { <span class="hljs-title">TUser</span>.<span class="hljs-title">class</span> };</span>
}
</code></pre>
<p>这样就表示作用在TUser类上，多个类可以追加。最终代码如下：</p>
<pre><code class="hljs">public <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StringRemarkFill</span> <span class="hljs-keyword"><span class="hljs-keyword">extends</span></span> <span class="hljs-title">BaseFill&lt;String&gt;</span> {</span>

	<span class="hljs-annotation">@Override</span>
	public <span class="hljs-type">String</span> getColumnName() {
		<span class="hljs-keyword">return</span> <span class="hljs-string">"remark"</span>;
	}

	<span class="hljs-annotation">@Override</span>
	public <span class="hljs-type">Class</span>&lt;?&gt;[] getTargetEntityClasses() {
		<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-type">Class</span>&lt;?&gt;[] { <span class="hljs-type">TUser</span>.<span class="hljs-keyword">class</span> }; <span class="hljs-comment">// 只作用在TUser类上</span>
	}

	<span class="hljs-annotation">@Override</span>
	public <span class="hljs-type">FillType</span> getFillType() {
		<span class="hljs-keyword">return</span> <span class="hljs-type">FillType</span>.<span class="hljs-type">INSERT</span>;
	}

	<span class="hljs-annotation">@Override</span>
	<span class="hljs-keyword">protected</span> <span class="hljs-type">Object</span> getFillValue(<span class="hljs-type">String</span> defaultValue) {
		<span class="hljs-keyword">return</span> <span class="hljs-string">"备注默认内容"</span>; <span class="hljs-comment">// insert时填充的内容</span>
	}

}
</code></pre>
<p>关于自动填充的原理是基于mybatis的TypeHandler实现的，这里就不多做介绍了。感兴趣的同学可以查看BaseFill&lt;T&gt;源码。</p>
<h1>主键策略设置</h1>
<p>跟hibernate的主键生成策略一致</p>
<h2>主键自增</h2>
<p>数据库主键设置自增后，这样设置：</p>
<pre><code class="hljs"><span class="hljs-annotation">@Id</span>
<span class="hljs-annotation">@Column</span>(name = <span class="hljs-string">"id"</span>)
<span class="hljs-annotation">@GeneratedValue</span>(strategy = GenerationType.IDENTITY) <span class="hljs-comment">// 其它数据库也要设置成GenerationType.IDENTITY，只要是自增</span>
<span class="hljs-keyword">private</span> Integer id;
</code></pre>
<p>这样在做insert后，id会自动填充自增后的值。</p>
<h2>主键使用uuid</h2>
<p>数据库主键是varchar类型，insert后自动填充uuid，并返回。</p>
<pre><code class="hljs"><span class="hljs-annotation">@Id</span>
<span class="hljs-annotation">@Column</span>(name = <span class="hljs-string">"id"</span>)
<span class="hljs-annotation">@GeneratedValue</span>(generator = <span class="hljs-string">"system-uuid"</span>)
<span class="hljs-keyword">private</span> String id;
</code></pre>
<p>这样在做insert后，id字段会自动填充uuid。</p>
<ul>
<li>注：uuid的生成方式是调用数据库底层实现，如MySql的实现方式为： SELECT UUID()</li>
</ul>
<h2>自定义uuid</h2>
<p>如果不希望使用底层数据库的uuid，可自定义自己实现，实现方式如下：</p>
<ul>
<li>首先entity中的id字段@GeneratedValue注解设置成AUTO</li>
</ul>
<pre><code class="hljs"><span class="hljs-variable">@Id</span>
<span class="hljs-variable">@Column</span>(name = <span class="hljs-string">"id"</span>)
<span class="hljs-variable">@GeneratedValue</span>(strategy=GenerationType.AUTO)
private String id;
</code></pre>
<ul>
<li>创建一个类UUIDFill并继承FillHandler类</li>
</ul>
<pre><code class="hljs"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UUIDFill</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">FillHandler</span>&lt;<span class="hljs-title">String</span>&gt; </span>{
	<span class="hljs-annotation">@Override</span>
	<span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getColumnName</span><span class="hljs-params">()</span> </span>{
		<span class="hljs-keyword">return</span> <span class="hljs-string">"id"</span>; <span class="hljs-comment">// 作用在id字段上</span>
	}
	<span class="hljs-annotation">@Override</span>
	<span class="hljs-function"><span class="hljs-keyword">public</span> FillType <span class="hljs-title">getFillType</span><span class="hljs-params">()</span> </span>{
		<span class="hljs-keyword">return</span> FillType.INSERT; <span class="hljs-comment">// INSERT时触发</span>
	}
	<span class="hljs-annotation">@Override</span>
	<span class="hljs-function"><span class="hljs-keyword">protected</span> Object <span class="hljs-title">getFillValue</span><span class="hljs-params">(String defaultValue)</span> </span>{
		<span class="hljs-keyword">return</span> UUID.randomUUID().toString(); <span class="hljs-comment">// 自定义的uuid生成方式</span>
	}
}
</code></pre>
<ul>
<li>在application.properties中添加</li>
</ul>
<pre><code class="hljs"># <span class="hljs-string">key:</span>填充器全路径类名,<span class="hljs-string">value:</span>构造函数参数值,没有可不填
mybatis.fill.com.xx.aa.UUIDFill=
</code></pre>
<p>格式为mybatis.fill.类路径=构造参数(没有可不填)</p>
<p>到此已经可以了，当进行insert操作后，id字段会自动插入自定义的uuid。</p>
<p>但是使用过程中还会有个问题，如果数据库中既有自增主键的表，也有自定义UUID主键的表，那么上面的做法就没办法区分了。因此我们要找出自定义UUID主键的表，解决办法是重写FillHandler的match(Class&lt;?&gt; entityClass, Field field, String columnName)方法，完整的代码如下：</p>
<pre><code class="hljs"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UUIDFill</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">FillHandler</span>&lt;<span class="hljs-title">String</span>&gt; </span>{
    <span class="hljs-comment">/* 重写方法，自定义匹配
        entityClass     实体类class
        field           字段信息
        columnName      给定的数据库字段名
    */</span>
    <span class="hljs-annotation">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">match</span><span class="hljs-params">(Class&lt;?&gt; entityClass, Field field, String columnName)</span> </span>{
        <span class="hljs-keyword">boolean</span> isPk = field.getAnnotation(Id.class) != <span class="hljs-keyword">null</span>; <span class="hljs-comment">// 是否有@Id注解</span>
        
        GeneratedValue gv = field.getAnnotation(GeneratedValue.class);
        <span class="hljs-keyword">boolean</span> isAuto = gv != <span class="hljs-keyword">null</span> &amp;&amp; gv.strategy() == GenerationType.AUTO; <span class="hljs-comment">// 是否有@GeneratedValue注解，并且策略是AUTO</span>
        
        <span class="hljs-keyword">return</span> isPk &amp;&amp; isAuto;
    }

    <span class="hljs-annotation">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getColumnName</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"id"</span>; <span class="hljs-comment">// 作用在id字段上</span>
    }
    <span class="hljs-annotation">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> FillType <span class="hljs-title">getFillType</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> FillType.INSERT; <span class="hljs-comment">// INSERT时触发</span>
    }
    <span class="hljs-annotation">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">protected</span> Object <span class="hljs-title">getFillValue</span><span class="hljs-params">(String defaultValue)</span> </span>{
        <span class="hljs-keyword">return</span> UUID.randomUUID().toString(); <span class="hljs-comment">// 自定义的uuid生成方式</span>
    }

}
</code></pre>
<p>这样就能区分出自增主键和自定义主键了。</p>
<p>此方式是采用<code>字段自动填充</code>功能实现。</p>
<h1>其他功能</h1>
<h2>指定外部模板</h2>
<p>fastmybatis依赖模板文件来生成mapper，默认的模板存放在fastmybatis/tpl/下，模板文件名对应某一种数据库，如mysql.vm对应mysql数据库。</p>
<p>我们可以通过更改template-classpath的值来改变模板读取的位置。默认template-classpath的值为/fastmybatis/tpl/。假如你想对mysql.vm做一些修改，那么可以按照如下步骤进行：</p>
<ol>
<li>使用解压工具解压fastmybatis.jar</li>
<li>在fastmybatis/tpl/下找到mysql.vm，拷贝一份出来，放到你的项目中的classpath下（src/main/resources）</li>
<li>在application.properties中添加一行</li>
</ol>
<pre><code class="hljs">mybatis.<span class="hljs-keyword">template</span>-classpath=/ 
</code></pre>
<p>这样在启动时会自动读取classpath根目录下的mysql.vm。控制台也会打印读取模板的信息：</p>
<pre><code class="hljs"><span class="hljs-number">2017</span>-<span class="hljs-number">12</span>-<span class="hljs-number">26</span> <span class="hljs-number">19</span>:<span class="hljs-number">32</span>:<span class="hljs-number">31.021</span>  INFO <span class="hljs-number">13476</span> --- [           main] n<span class="hljs-class">.o</span><span class="hljs-class">.d</span><span class="hljs-class">.e</span><span class="hljs-class">.ext</span><span class="hljs-class">.MapperLocationsBuilder</span>       : 使用模板:/mysql<span class="hljs-class">.vm</span>
</code></pre>
<p>如果你的项目是springmvc，采用xml配置形式，前两步不变，第三步改为：</p>
<pre><code class="hljs"><span class="hljs-comment">&lt;!-- 替换org.mybatis.spring.SqlSessionFactoryBean --&gt;</span>
	<span class="hljs-tag">&lt;<span class="hljs-title">bean</span> <span class="hljs-attribute">id</span>=<span class="hljs-value">"sqlSessionFactory"</span>
		<span class="hljs-attribute">class</span>=<span class="hljs-value">"com.gitee.fastmybatis.core.ext.SqlSessionFactoryBeanExt"</span>&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-title">property</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"dataSource"</span> <span class="hljs-attribute">ref</span>=<span class="hljs-value">"dataSource"</span> /&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-title">property</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"configLocation"</span>&gt;</span>
			<span class="hljs-tag">&lt;<span class="hljs-title">value</span>&gt;</span>classpath:mybatis/mybatisConfig.xml<span class="hljs-tag">&lt;/<span class="hljs-title">value</span>&gt;</span>
		<span class="hljs-tag">&lt;/<span class="hljs-title">property</span>&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-title">property</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"mapperLocations"</span>&gt;</span>
			<span class="hljs-tag">&lt;<span class="hljs-title">list</span>&gt;</span>
				<span class="hljs-tag">&lt;<span class="hljs-title">value</span>&gt;</span>classpath:mybatis/mapper/*.xml<span class="hljs-tag">&lt;/<span class="hljs-title">value</span>&gt;</span>
			<span class="hljs-tag">&lt;/<span class="hljs-title">list</span>&gt;</span>
		<span class="hljs-tag">&lt;/<span class="hljs-title">property</span>&gt;</span>
		
		<span class="hljs-comment">&lt;!-- 以下是附加属性 --&gt;</span>
		
		<span class="hljs-comment">&lt;!-- dao所在的包名,跟MapperScannerConfigurer的basePackage一致 
			多个用;隔开
		--&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-title">property</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"basePackage"</span> <span class="hljs-attribute">value</span>=<span class="hljs-value">"com.myapp.dao"</span> /&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-title">property</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"config"</span>&gt;</span>
			<span class="hljs-tag">&lt;<span class="hljs-title">bean</span> <span class="hljs-attribute">class</span>=<span class="hljs-value">"com.gitee.fastmybatis.core.FastmybatisConfig"</span>&gt;</span>
				<span class="hljs-comment">&lt;!-- 指定外部模板 --&gt;</span>
				<span class="hljs-tag">&lt;<span class="hljs-title">property</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"templateClasspath"</span> <span class="hljs-attribute">value</span>=<span class="hljs-value">"/"</span>/&gt;</span>
			<span class="hljs-tag">&lt;/<span class="hljs-title">bean</span>&gt;</span>
		<span class="hljs-tag">&lt;/<span class="hljs-title">property</span>&gt;</span>
	<span class="hljs-tag">&lt;/<span class="hljs-title">bean</span>&gt;</span>
</code></pre>
<h2>逻辑删除</h2>
<p>即更新一个字段标记为已删除。查询的时候会自动过滤掉已删除的数据。</p>
<p>假设数据库表中有一个字段is_deleted类型为tinyint，0表示未删除，1表示已删除。</p>
<p>实体类对应代码如下：</p>
<pre><code class="hljs"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> </span>{
    <span class="hljs-annotation">@LogicDelete</span>
    <span class="hljs-keyword">private</span> Byte isDeleted;
}
</code></pre>
<p>在执行<code>mapper.delete(1L);</code>时会触发UPDATE语句，将is_deleted字段更新为1。</p>
<p>如果is_deleted类型为char(1)，f表示未删除，t表示已删除。</p>
<pre><code class="hljs"><span class="hljs-annotation">@LogicDelete</span>(notDeleteValue = <span class="hljs-string">"f"</span>, deleteValue = <span class="hljs-string">"t"</span>)
<span class="hljs-keyword">private</span> String isDeleted;
</code></pre>
<p>@LogicDelete提供两个属性</p>
<ul>
<li>notDeleteValue：指定未删除时的值,不指定默认为0</li>
<li>deleteValue：指定删除后保存的值,不指定默认为1</li>
</ul>
<p>假设1表示未删除，2表示已删除，@LogicDelete的设置方法如下：@LogicDelete(notDeleteValue = “1”, deleteValue = “2”)。如果每个实体类都要这样设置的话会很麻烦，fastmybatis提供了全局配置</p>
<ul>
<li>springboot下，application.properties添加</li>
</ul>
<pre><code class="hljs"><span class="hljs-comment"># 未删除数据库保存的值，默认为0</span>
mybatis.logic-<span class="hljs-operator">not</span>-<span class="hljs-built_in">delete</span>-<span class="hljs-built_in">value</span>=<span class="hljs-number">1</span>
<span class="hljs-comment"># 删除后数据库保存的值，默认为1</span>
mybatis.logic-<span class="hljs-built_in">delete</span>-<span class="hljs-built_in">value</span>=<span class="hljs-number">2</span>
</code></pre>
<ul>
<li>springmvc设置方式如下：</li>
</ul>
<pre><code class="hljs"><span class="hljs-comment">&lt;!-- 替换org.mybatis.spring.SqlSessionFactoryBean --&gt;</span>
	<span class="hljs-tag">&lt;<span class="hljs-title">bean</span> <span class="hljs-attribute">id</span>=<span class="hljs-value">"sqlSessionFactory"</span>
		<span class="hljs-attribute">class</span>=<span class="hljs-value">"com.gitee.fastmybatis.core.ext.SqlSessionFactoryBeanExt"</span>&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-title">property</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"dataSource"</span> <span class="hljs-attribute">ref</span>=<span class="hljs-value">"dataSource"</span> /&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-title">property</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"configLocation"</span>&gt;</span>
			<span class="hljs-tag">&lt;<span class="hljs-title">value</span>&gt;</span>classpath:mybatis/mybatisConfig.xml<span class="hljs-tag">&lt;/<span class="hljs-title">value</span>&gt;</span>
		<span class="hljs-tag">&lt;/<span class="hljs-title">property</span>&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-title">property</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"mapperLocations"</span>&gt;</span>
			<span class="hljs-tag">&lt;<span class="hljs-title">list</span>&gt;</span>
				<span class="hljs-tag">&lt;<span class="hljs-title">value</span>&gt;</span>classpath:mybatis/mapper/*.xml<span class="hljs-tag">&lt;/<span class="hljs-title">value</span>&gt;</span>
			<span class="hljs-tag">&lt;/<span class="hljs-title">list</span>&gt;</span>
		<span class="hljs-tag">&lt;/<span class="hljs-title">property</span>&gt;</span>
		
		<span class="hljs-comment">&lt;!-- 以下是附加属性 --&gt;</span>
		
		<span class="hljs-comment">&lt;!-- dao所在的包名,跟MapperScannerConfigurer的basePackage一致 
			多个用;隔开
		--&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-title">property</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"basePackage"</span> <span class="hljs-attribute">value</span>=<span class="hljs-value">"com.myapp.dao"</span> /&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-title">property</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"config"</span>&gt;</span>
			<span class="hljs-tag">&lt;<span class="hljs-title">bean</span> <span class="hljs-attribute">class</span>=<span class="hljs-value">"com.gitee.fastmybatis.core.FastmybatisConfig"</span>&gt;</span>		
				<span class="hljs-tag">&lt;<span class="hljs-title">property</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"logicNotDeleteValue"</span> <span class="hljs-attribute">value</span>=<span class="hljs-value">"1"</span>/&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-title">property</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"logicDeleteValue"</span> <span class="hljs-attribute">value</span>=<span class="hljs-value">"2"</span>/&gt;</span>
			<span class="hljs-tag">&lt;/<span class="hljs-title">bean</span>&gt;</span>
		<span class="hljs-tag">&lt;/<span class="hljs-title">property</span>&gt;</span>
	<span class="hljs-tag">&lt;/<span class="hljs-title">bean</span>&gt;</span>
</code></pre>
<ul>
<li>注：如果同时设置了@LogicDelete参数和全局配置，会优先读取注解中的配置。</li>
</ul>
<hr>
<h3>代码生成器自动生成<code>@LogicDelete</code>注解</h3>
<p>使用代码生成器生成实体类的时候，如果指定了删除字段，可自动在该字段上面加上<code>@LogicDelete</code>注解。</p>
<p>步骤如下：</p>
<p>打开代码生成器对应的属性文件，添加一行</p>
<p><code>deleteColumn=isdel</code></p>
<p>其中<code>isdel</code>表示表中的删除字段，生成后的效果</p>
<pre><code class="hljs">/<span class="hljs-keyword">*</span><span class="hljs-keyword">*</span>
 <span class="hljs-keyword">*</span> 表名：t_user
 <span class="hljs-keyword">*</span> 备注：用户表
 <span class="hljs-keyword">*</span>/
<span class="hljs-comment">@Table(name = "t_user")</span>
public class User {
    <span class="hljs-comment">@Id</span>
    <span class="hljs-comment">@Column(name = "id")</span>
    <span class="hljs-comment">@GeneratedValue(strategy = GenerationType.IDENTITY)</span>
    /<span class="hljs-keyword">*</span><span class="hljs-keyword">*</span> ID, 数据库字段：id <span class="hljs-keyword">*</span>/
    private Integer id;

    /<span class="hljs-keyword">*</span><span class="hljs-keyword">*</span> 用户名, 数据库字段：username <span class="hljs-keyword">*</span>/
    private String username;

    /<span class="hljs-keyword">*</span><span class="hljs-keyword">*</span> 状态, 数据库字段：state <span class="hljs-keyword">*</span>/
    private Byte state;

    /<span class="hljs-keyword">*</span><span class="hljs-keyword">*</span> 是否删除, 数据库字段：isdel <span class="hljs-keyword">*</span>/
    <span class="hljs-comment">@com.gitee.fastmybatis.core.annotation.LogicDelete</span>
    private Boolean isdel;

...
}
</code></pre>
<p>可查看fastmybatis-generator项目中的t_user_all.properties文件，然后运行Run_t_userAll.java进行体验</p>
<h1>实体类懒加载（一对一）</h1>
<p>有两张表</p>
<ul>
<li>用户表</li>
</ul>
<pre><code class="hljs"><span class="hljs-operator"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`t_user`</span> (
  <span class="hljs-string">`id`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> auto_increment COMMENT <span class="hljs-string">'ID'</span>,
  <span class="hljs-string">`username`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">default</span> <span class="hljs-literal">NULL</span> COMMENT <span class="hljs-string">'用户名'</span>,
  <span class="hljs-string">`state`</span> tinyint(<span class="hljs-number">4</span>) <span class="hljs-keyword">default</span> <span class="hljs-literal">NULL</span> COMMENT <span class="hljs-string">'状态'</span>,
  <span class="hljs-string">`isdel`</span> <span class="hljs-built_in">bit</span>(<span class="hljs-number">1</span>) <span class="hljs-keyword">default</span> <span class="hljs-literal">NULL</span> COMMENT <span class="hljs-string">'是否删除'</span>,
  <span class="hljs-string">`remark`</span> <span class="hljs-built_in">text</span> COMMENT <span class="hljs-string">'备注'</span>,
  <span class="hljs-string">`create_time`</span> datetime <span class="hljs-keyword">default</span> <span class="hljs-literal">NULL</span> COMMENT <span class="hljs-string">'添加时间'</span>,
  <span class="hljs-string">`money`</span> <span class="hljs-built_in">decimal</span>(<span class="hljs-number">10</span>,<span class="hljs-number">2</span>) <span class="hljs-keyword">default</span> <span class="hljs-literal">NULL</span> COMMENT <span class="hljs-string">'金额'</span>,
  <span class="hljs-string">`left_money`</span> <span class="hljs-built_in">float</span> <span class="hljs-keyword">default</span> <span class="hljs-literal">NULL</span> COMMENT <span class="hljs-string">'剩下的钱'</span>,
  <span class="hljs-keyword">PRIMARY</span> <span class="hljs-keyword">KEY</span>  (<span class="hljs-string">`id`</span>)
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> AUTO_INCREMENT=<span class="hljs-number">10</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8 COMMENT=<span class="hljs-string">'用户表'</span>
</span></code></pre>
<ul>
<li>用户信息表</li>
</ul>
<pre><code class="hljs"><span class="hljs-operator"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`user_info`</span> (
  <span class="hljs-string">`id`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">10</span>) unsigned <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> auto_increment,
  <span class="hljs-string">`user_id`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> COMMENT <span class="hljs-string">'t_user对应主键'</span>,
  <span class="hljs-string">`address`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">default</span> <span class="hljs-literal">NULL</span> COMMENT <span class="hljs-string">'地址'</span>,
  <span class="hljs-keyword">PRIMARY</span> <span class="hljs-keyword">KEY</span>  (<span class="hljs-string">`id`</span>)
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> AUTO_INCREMENT=<span class="hljs-number">3</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8

</span></code></pre>
<p>假设在查询<code>user_info</code>表时懒加载关联<code>t_user</code>表，实体类对应如下：</p>
<pre><code class="hljs">/<span class="hljs-keyword">*</span><span class="hljs-keyword">*</span>
 <span class="hljs-keyword">*</span> 表名：t_user
 <span class="hljs-keyword">*</span> 备注：用户表
 <span class="hljs-keyword">*</span>/
<span class="hljs-comment">@Table(name = "t_user")</span>
public class TUser {
    <span class="hljs-comment">@Id</span>
    <span class="hljs-comment">@Column(name = "id")</span>
    <span class="hljs-comment">@GeneratedValue(strategy = GenerationType.IDENTITY)</span>
    /<span class="hljs-keyword">*</span><span class="hljs-keyword">*</span> ID, 数据库字段：id <span class="hljs-keyword">*</span>/
    private Integer id;

    /<span class="hljs-keyword">*</span><span class="hljs-keyword">*</span> 用户名, 数据库字段：username <span class="hljs-keyword">*</span>/
    private String username;

    /<span class="hljs-keyword">*</span><span class="hljs-keyword">*</span> 状态, 数据库字段：state <span class="hljs-keyword">*</span>/
    private Byte state;

    /<span class="hljs-keyword">*</span><span class="hljs-keyword">*</span> 是否删除, 数据库字段：isdel <span class="hljs-keyword">*</span>/
    <span class="hljs-comment">@com.gitee.fastmybatis.core.annotation.LogicDelete</span>
    private Boolean isdel;

    /<span class="hljs-keyword">*</span><span class="hljs-keyword">*</span> 备注, 数据库字段：remark <span class="hljs-keyword">*</span>/
    private String remark;

    /<span class="hljs-keyword">*</span><span class="hljs-keyword">*</span> 添加时间, 数据库字段：create_time <span class="hljs-keyword">*</span>/
    private Date createTime;

    /<span class="hljs-keyword">*</span><span class="hljs-keyword">*</span> 金额, 数据库字段：money <span class="hljs-keyword">*</span>/
    private BigDecimal money;

    /<span class="hljs-keyword">*</span><span class="hljs-keyword">*</span> 剩下的钱, 数据库字段：left_money <span class="hljs-keyword">*</span>/
    private Float leftMoney;

// getter setter
}
</code></pre>
<p>t_user对应的实体类常规方式，不变。</p>
<pre><code class="hljs"><span class="hljs-keyword">@Table</span>(name = <span class="hljs-string">"user_info"</span>)
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> UserInfo {
	<span class="hljs-keyword">@Id</span>
	<span class="hljs-keyword">@Column</span>(name = <span class="hljs-string">"id"</span>)
	<span class="hljs-keyword">@GeneratedValue</span>(strategy = GenerationType.IDENTITY)
	<span class="hljs-comment">/** 数据库字段：id */</span>
	<span class="hljs-keyword">private</span> Integer id;

	<span class="hljs-comment">// 一对一配置，这里的user_id对应TUser主键</span>
	<span class="hljs-comment">// 触发懒加载时，会拿user_id的值去查询t_user表</span>
	<span class="hljs-comment">// 即：SELECT * FROM t_user WHERE id={user_id}</span>
	<span class="hljs-keyword">@Column</span>(name = <span class="hljs-string">"user_id"</span>)
	<span class="hljs-keyword">private</span> TUser user;

	<span class="hljs-comment">/** 地址, 数据库字段：address */</span>
	<span class="hljs-keyword">private</span> String address;

    <span class="hljs-comment">// getter setter</span>

}
</code></pre>
<p>user_info对应的实体类，本来user_id部分变成</p>
<pre><code class="hljs"><span class="hljs-annotation">@Column</span>(name = <span class="hljs-string">"user_id"</span>)
<span class="hljs-keyword">private</span> TUser user;
</code></pre>
<ul>
<li>测试用例：</li>
</ul>
<pre><code class="hljs">@Autowired
	UserInfoMapper mapper<span class="hljs-comment">;</span>
	
	@Test
	public void testGet() {
		UserInfo userInfo = mapper.getById(<span class="hljs-number">2</span>)<span class="hljs-comment">;</span>
		System.out.println(userInfo.getAddress())<span class="hljs-comment">;</span>
		// 这里触发懒加载，将会执行
		// SELECT t.<span class="hljs-escape">`i</span>d<span class="hljs-escape">` </span>, t.<span class="hljs-escape">`u</span>sername<span class="hljs-escape">` </span>, t.<span class="hljs-escape">`s</span>tate<span class="hljs-escape">` </span>, t.<span class="hljs-escape">`i</span>sdel<span class="hljs-escape">` </span>, t.<span class="hljs-escape">`r</span>emark<span class="hljs-escape">` </span>, t.<span class="hljs-escape">`a</span>dd_time<span class="hljs-escape">` </span>, t.<span class="hljs-escape">`m</span>oney<span class="hljs-escape">` </span>, t.<span class="hljs-escape">`l</span>eft_money<span class="hljs-escape">` </span>FROM <span class="hljs-escape">`t</span>_user<span class="hljs-escape">` </span>t WHERE <span class="hljs-escape">`i</span>d<span class="hljs-escape">` </span>= ? <span class="hljs-literal">AND</span> t.isdel = <span class="hljs-number">0</span> LIMIT <span class="hljs-number">1</span> 
		// 可将下面两句注释查看sql执行情况
		TUser user = userInfo.getUser()<span class="hljs-comment">;</span>
		System.out.println(user)<span class="hljs-comment">;</span>
	}
</code></pre>
</div>
<!-- ***********************************************************内容分割线***************************************************** -->
                </article>
            </div>
        </div>
    <script src="./static/jquery-1.10.2.min.js"></script>
    <script src="./static/jquery.ztree.all-3.5.min.js"></script>
    <script src="./static/jquery.ztree_toc.min.js"></script>
    <script type="text/javascript">
    var title = document.title;
        $(document).ready(function(){
            $('#tree').ztree_toc({
            	_header_nodes: [{ id:1, pId:0, name:title,open:false}],  // 第一个节点
            	ztreeSetting: {
            		view: {
        				dblClickExpand: false,
        				showLine: true,
        				showIcon: false,
        				selectedMulti: false
        			},
        			data: {
        				simpleData: {
        					enable: true,
        					idKey : "id",
        					pIdKey: "pId"
        					// rootPId: "0"
        				}
        			},
            		callback: {
        				beforeClick: function(treeId, treeNode) {
        					$('a').removeClass('curSelectedNode');
        					if(treeNode.id == 1){
        						$('body').scrollTop(0);
        					}
        					if($.fn.ztree_toc.defaults.is_highlight_selected_line == true) {
        						$('#' + treeNode.id).css('color' ,'red').fadeOut("slow" ,function() {
        							$(this).show().css('color','black');
        						});
        					}
        				}
        			}            		
            	},
                is_auto_number:true, // 菜单是否显示编号，如果markdown标题没有数字标号可以设为true
                documment_selector:'.markdown-body',
                is_expand_all: true // 菜单全部展开
            });
            // 代码高亮
            $('.highlight').each(function(i, block) {
          	    hljs.highlightBlock(block);
          	});
        });
    </script>
    </body>
</html>